/**
 *  @file BasicOperate.c
 *  @desc 实现双向循环链表的基本操作，包括初始化、插入、删除、打印等功能
 *  @author WangBlue(wangjiping596@gmail.com)
 *  @date 2025-07-23 14:15
 *  @version 1.0
 */

#include <stdio.h>
#include <stdlib.h>

// 双向链表节点结构定义
typedef struct node {
    int data;            // 数据域
    struct node *next;   // 后继指针
    struct node *pre;    // 前驱指针
} node, *link;

/**
 * @brief 创建一个新节点
 * @param value 新节点要存储的数据
 * @return 创建成功返回新节点指针，失败返回 NULL
 */
link createNode(int value) {
    link newNode = (link) malloc(sizeof(node));
    if (newNode == NULL) return NULL;
    newNode->next = NULL;
    newNode->pre = NULL;
    newNode->data = value;
    return newNode;
}

/**
 * @brief 初始化双向循环链表的头节点
 * @param head 传入链表头指针的地址，初始化后指向一个头节点（不存储有效数据）
 */
void initNode(link *head) {
    link newNode = createNode(0);  // 创建头节点
    if (newNode == NULL) return;
    *head = newNode;

    // 自环，形成循环结构
    (*head)->next = *head;
    (*head)->pre  = *head;
}

/**
 * @brief 头插法插入一个新节点
 * @param head 链表头指针
 * @param value 要插入的新节点的值
 */
void istHead(link head, int value) {
    link newNode = createNode(value);
    if (newNode == NULL) return;

    newNode->next = head->next;  // 新节点指向原第一个节点
    head->next->pre = newNode;   // 原第一个节点前驱变为新节点

    head->next = newNode;        // 头节点指向新节点
    newNode->pre  = head;        // 新节点前驱是头节点
}

/**
 * @brief 尾插法插入一个新节点
 * @param head 链表头指针
 * @param value 要插入的新节点的值
 */
void istTail(link head, int value) {
    link newNode = createNode(value);
    if (newNode == NULL) return;

    link last = head->pre;  // 获取尾节点（head->pre 指向尾）

    newNode->pre = last;
    newNode->next = head;

    last->next = newNode;
    head->pre = newNode;  // 更新 head 的前驱指向新尾节点
}

/**
 * @brief 打印链表中所有节点的值（不包括头节点）
 * @param head 链表头节点指针
 */
void printList(link head) {
    if (head == NULL || head->next == NULL) return;

    link cur = head->next;
    while (cur != head) {  // 遇到头节点表示遍历完成
        printf("value is %d\n", cur->data);
        cur = cur->next;
    }
    printf("\n");
}

/**
 * @brief 删除指定位置的节点（位置从1开始，不包含头节点）
 * @param head 链表头节点指针
 * @param pos 要删除的位置
 */
void delByPos(link head, int pos) {
    if (head == NULL || head->next == head || pos < 1) return;

    link cur = head->next;
    int idx = 1;
    while (cur != head && idx < pos) {  // 遍历到第 pos 个节点
        cur = cur->next;
        idx++;
    }

    if (cur == head) return;  // 超出链表长度

    // 修改指针，跳过当前节点
    cur->pre->next = cur->next;
    cur->next->pre = cur->pre;

    free(cur);  // 释放当前节点
}

/**
 * @brief 在指定位置插入一个新节点（位置从1开始，插入在第 pos 个位置之前）
 * @param head 链表头节点指针
 * @param pos 要插入的位置（从1开始）
 * @param value 要插入的值
 */
void istByPos(link head, int pos, int value) {
    if ( pos < 1) return;

    link cur = head;
    int idx = 0;

    // 找到插入位置的前一个节点
    while (cur->next != head && idx < pos - 1) {
        cur = cur->next;
        idx++;
    }

    if (idx != pos - 1) return;  // 位置非法或越界

    link newNode = createNode(value);
    if (newNode == NULL) return;

    newNode->next = cur->next;
    newNode->pre = cur;

    cur->next->pre = newNode;
    cur->next = newNode;
}

/**
 * @brief 主函数，测试链表操作
 */
int main() {
    link head = NULL;

    // 初始化循环双向链表
    initNode(&head);

    // 插入一些数据（尾插）
    istHead(head, 1);
    istHead(head, 2);
    istHead(head, 3);

    // 在第1个位置插入值为0的节点
    istByPos(head, 1, 0);

    // 输出链表数据
    printList(head);

    // 可选：删除、插入其他位置进行更多测试
    // delByPos(head, 3);
    // istByPos(head, 2, 99);

    return 0;
}
